/*
the prototype of a service.

a service runs on another process or a remote server;
a service should be 1.registered 2.mounted 3.started

host(client) can send a request to the service;
support sync and async response;
support status update (streaming data) from service to host;

support cancel a request at any time;
*/
use std::{
    collections::{HashMap, HashSet}, fs, path::Path, sync::{Arc, Mutex}
};
use once_cell::sync::OnceCell;
use rocket::{fairing::{Fairing, Info, Kind}, Rocket, Orbit};
use tokio::time::Instant;
use super::{
    builtin_service::{get_builtin_services, get_test_services},
    service::{Service, ServiceStructA, ServiceStatus}
};
use crate::{
    error::ServerError,
    protocol::service::{addr2id, Addr, ServiceId}, services::builtin_service
};

#[derive(Debug)]
pub struct ServiceManager {
    pub services: HashMap<ServiceId, Service>,
    json_path: &'static str,
    sites_path: &'static str,
}

impl ServiceManager {
    pub fn new() -> Self {
        Self {
            services: HashMap::new(),
            json_path: "edp_files/system/services.json",
            sites_path: "edp_files/system/service-sites.json",
        }
    }

    pub async fn load_sites(&mut self) -> Result<(), ServerError> {
        let path = Path::new(&self.sites_path);
        let content = fs::read_to_string(path).unwrap();
        let sites: Vec<String> = serde_json::from_str(&content).unwrap();
        for site in sites {
            let service = Service::new(site.clone())?;
            mark_for_async_register(service).await;
        }
        Ok(())
    }

    #[deprecated]
    pub fn load_from_json(&mut self) -> Result<(), ServerError> {
        let path = Path::new(&self.json_path);
        let content = fs::read_to_string(path).unwrap();
        let services: Vec<Service> = serde_json::from_str(&content).unwrap();
        self.add_services(services);
        Ok(())
    }

    pub fn save_to_disk(&self) -> Result<(), ServerError> {
        let services = self.get_services();
        let sites = services.values().map(|x|x.address.clone()).collect::<Vec<Addr>>();
        let content = serde_json::to_string(services).unwrap();
        if !Path::new(&self.json_path).exists() {
            let path = Path::new(&self.json_path).parent().unwrap();
            println!("create dir: {:?}", path);
            fs::create_dir_all(path).unwrap();
        }
        fs::write(&self.json_path, content).unwrap();
        let content = serde_json::to_string(&sites).unwrap();
        if !Path::new(&self.sites_path).exists() {
            let path = Path::new(&self.sites_path).parent().unwrap();
            println!("create dir: {:?}", path);
            fs::create_dir_all(path).unwrap();
        }
        fs::write(&self.sites_path, content).unwrap();
        Ok(())
    }

    pub fn get_service(&self, service_id: &ServiceId) -> Option<Service> {
        self.services.get(service_id).map(|x|x.clone())
    }

    fn add_service(&mut self, service: Service) {
        self.services.insert(addr2id(service.address.clone()), service);
    }

    pub fn renew_service(&mut self, service: &Service) {
        self.services.insert(addr2id(service.address.clone()), service.clone());
    }

    pub fn add_services(&mut self, services: Vec<Service>) {
        for service in services {
            self.add_service(service);
        }
    }

    pub fn get_services(&self) -> &HashMap<ServiceId, Service> {
        &self.services
    }

    pub fn remove_service(&mut self, id: String) {
        self.services.remove(&id);
    }

    pub fn set_service_status(&mut self, id: &str, status: ServiceStatus) -> Result<(), ServerError> {
        if let Some(service) = self.services.get_mut(id) {
            service.status = status;
            Ok(())
        } else {
            Err(ServerError::ServiceError(format!("服务不存在: {}", id)))
        }
    }
}

pub static SERVICE_MANAGER: OnceCell<Arc<tokio::sync::Mutex<ServiceManager>>> = OnceCell::new();

macro_rules! get_manager {
    () => {
        SERVICE_MANAGER.get().unwrap().lock().await
    };
}

async fn mark_for_async_register(mut service: Service) {
    let handle = std::thread::spawn(move || {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async move {
            let _ = service.register().await;
            service.merge_given_info();
            let mut manager = get_manager!();
            manager.add_service(service);
        });
    });
}

async fn mark_for_async_refresh_register(service_id: ServiceId) {
    let handle = std::thread::spawn(move || {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async move {
            let mut service = {
                let manager = get_manager!();
                manager.get_service(&service_id).unwrap().clone()
        };
        let res = service.register().await;
        let _ = res.map_err(|e|eprintln!("{:?}", e));
        let mut manager = get_manager!();
        manager.renew_service(&service);
        });
    });
}

pub async fn service_struct_from_client(recv: ServiceStructA) -> Result<(), ServerError> {
    let service = receive_from_client(recv).await?;
    mark_for_async_register(service).await;
    Ok(())
}

pub async fn receive_from_client(recv: ServiceStructA) -> Result<Service, ServerError> {
    let addr = recv.address.clone();
    let manager = get_manager!();
    if manager.get_service(&addr).is_some() {
        return Err(ServerError::ServiceErrorStr("服务已存在"));
    }
    let service = Service::from_recv(recv)?;
    Ok(service)
}

pub async fn refresh_service_from_client(service_id: String) -> Result<(), ServerError> {
    mark_for_async_refresh_register(service_id).await;
    Ok(())
}

pub struct ServiceManagerFairing;

#[rocket::async_trait]
impl Fairing for ServiceManagerFairing {
    fn info(&self) -> Info {
        Info {
            name: "Service Manager",
            kind: Kind::Shutdown
        }
    }

    async fn on_shutdown(&self, _rocket: &Rocket<Orbit>) {
        if let Some(manager) = SERVICE_MANAGER.get() {
            let manager = manager.lock().await;
            if let Err(e) = manager.save_to_disk() {
                eprintln!("Failed to save services to disk: {:?}", e);
            }
        }
    }
}

fn get_services_from_json(filepath: &'static str) -> Vec<String> {
    let path = Path::new(filepath);
    let content = fs::read_to_string(path).unwrap();
    let services: Vec<String> = serde_json::from_str(&content).unwrap();
    services
}

pub fn get_system_services() -> Vec<String> {
    get_services_from_json("static/system/service-sites.json")
}

pub fn init_service_manager() -> Result<(), ServerError> {
    let start = Instant::now();
    let mut manager = ServiceManager::new();
    // let services = get_test_services();
    // let builtin_services = get_builtin_services();
    let system_services = get_system_services();
    let last_services = get_services_from_json(manager.sites_path);
    let mut services_set = HashSet::new();
    // for each in builtin_services { services_set.insert(each.address); }
    for each in system_services { services_set.insert(each); }
    for each in last_services { services_set.insert(each); }
    let mut services = vec![];
    for each in services_set {
        services.push(Service::new(each)?);
    }
    let rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async {
        let mut handles = Vec::new();
        for mut service in services {
            handles.push(tokio::spawn(async move {
                let _ = service.register().await;
                service
            }));
        }
        for handle in handles {
            let service = handle.await.unwrap();
            manager.add_service(service);
        }
    });
    
    println!("service initial register finish in {:?} seconds", start.elapsed().as_secs());
    SERVICE_MANAGER.set(Arc::new(tokio::sync::Mutex::new(manager))).map_err(|_| ServerError::SystemErrorStr("服务管理器初始化失败"))?;
    Ok(())
}
